home *** CD-ROM | disk | FTP | other *** search
/ Computer Shopper 242 / Issue 242 - April 2008 - DPCS0408DVD.ISO / Open Source / AutoHotKey / Source / AutoHotkey104705_source.exe / source / var.h < prev    next >
Encoding:
C/C++ Source or Header  |  2007-05-24  |  17.7 KB  |  360 lines

  1. /*
  2. AutoHotkey
  3.  
  4. Copyright 2003-2007 Chris Mallett (support@autohotkey.com)
  5.  
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 2
  9. of the License, or (at your option) any later version.
  10.  
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15. */
  16.  
  17. #ifndef var_h
  18. #define var_h
  19.  
  20. #include "defines.h"
  21. #include "SimpleHeap.h"
  22. #include "clipboard.h"
  23. #include "util.h" // for strlcpy() & snprintf()
  24. EXTERN_CLIPBOARD;
  25.  
  26. #define MAX_ALLOC_SIMPLE 64  // Do not decrease this much since it is used for the sizing of some built-in variables.
  27. #define SMALL_STRING_LENGTH (MAX_ALLOC_SIMPLE - 1)  // The largest string that can fit in the above.
  28. #define DEREF_BUF_EXPAND_INCREMENT (16 * 1024) // Reduced from 32 to 16 in v1.0.46.07 to reduce the memory utilization of deeply recursive UDFs.
  29. #define ERRORLEVEL_NONE "0"
  30. #define ERRORLEVEL_ERROR "1"
  31. #define ERRORLEVEL_ERROR2 "2"
  32.  
  33. enum AllocMethod {ALLOC_NONE, ALLOC_SIMPLE, ALLOC_MALLOC};
  34. enum VarTypes
  35. {
  36.   // The following must all be LOW numbers to avoid any realistic chance of them matching the address of
  37.   // any function (namely a BIV_* function).
  38.   VAR_ALIAS  // VAR_ALIAS must always have a non-NULL mAliasFor.  In other ways it's the same as VAR_NORMAL.  VAR_ALIAS is never seen because external users call Var::Type(), which automatically resolves ALIAS to some other type.
  39. , VAR_NORMAL // Most variables, such as those created by the user, are this type.
  40. , VAR_CLIPBOARD
  41. , VAR_LAST_WRITABLE = VAR_CLIPBOARD  // Keep this in sync with any changes to the set of writable variables.
  42. #define VAR_IS_READONLY(var) ((var).Type() > VAR_LAST_WRITABLE)
  43. , VAR_CLIPBOARDALL // Must be read-only because it's not designed to be writable.
  44. , VAR_BUILTIN
  45. , VAR_LAST_TYPE = VAR_BUILTIN
  46. };
  47.  
  48. typedef UCHAR VarTypeType;     // UCHAR vs. VarTypes to save memory.
  49. typedef UCHAR AllocMethodType; // UCHAR vs. AllocMethod to save memory.
  50. typedef UCHAR VarAttribType;   // Same.
  51. typedef DWORD VarSizeType;     // Up to 4 gig if sizeof(UINT) is 4.  See next line.
  52. #define VARSIZE_MAX MAXDWORD
  53. #define VARSIZE_ERROR VARSIZE_MAX
  54. #define MAX_FORMATTED_NUMBER_LENGTH 255 // Large enough to allow custom zero or space-padding via %10.2f, etc.  But not too large because some things might rely on this being fairly small.
  55.  
  56.  
  57. class Var; // Forward declaration.
  58. struct VarBkp // This should be kept in sync with any changes to the Var class.  See Var for comments.
  59. {
  60.     Var *mVar; // Used to save the target var to which these backed up contents will later be restored.
  61.     char *mContents;
  62.     union
  63.     {
  64.         VarSizeType mLength;
  65.         Var *mAliasFor;
  66.     };
  67.     VarSizeType mCapacity;
  68.     AllocMethodType mHowAllocated;
  69.     VarAttribType mAttrib;
  70.     // Not needed in the backup:
  71.     //bool mIsLocal;
  72.     //VarTypeType mType;
  73.     //char *mName;
  74. };
  75.  
  76. typedef VarSizeType (* BuiltInVarType)(char *aBuf, char *aVarName);
  77. class Var
  78. {
  79. private:
  80.     // Keep VarBkp (above) in sync with any changes made to the members here.
  81.     char *mContents;
  82.     union
  83.     {
  84.         VarSizeType mLength;  // How much is actually stored in it currently, excluding the zero terminator.
  85.         Var *mAliasFor;       // The variable for which this variable is an alias.
  86.     };
  87.     union
  88.     {
  89.         VarSizeType mCapacity; // In bytes.  Includes the space for the zero terminator.
  90.         BuiltInVarType mBIV;
  91.     };
  92.     AllocMethodType mHowAllocated; // Keep adjacent/contiguous with the below to save memory.
  93.     #define VAR_ATTRIB_BINARY_CLIP  0x01
  94.     #define VAR_ATTRIB_PARAM        0x02 // Currently unused.
  95.     #define VAR_ATTRIB_STATIC       0x04 // Next in series would be 0x08, 0x10, etc.
  96.     VarAttribType mAttrib;  // Bitwise combination of the above flags.
  97.     bool mIsLocal;
  98.     VarTypeType mType; // Keep adjacent/contiguous with the above due to struct alignment, to save memory.
  99.     // Performance: Rearranging mType and the other byte-sized members with respect to each other didn't seem
  100.     // to help performance.  However, changing VarTypeType from UCHAR to int did boost performance a few percent,
  101.     // but even if it's not a fluke, it doesn't seem worth the increase in memory for scripts with many
  102.     // thousands of variables.
  103.  
  104. public:
  105.     // Testing shows that due to data alignment, keeping mType adjacent to the other less-than-4-size member
  106.     // above it reduces size of each object by 4 bytes.
  107.     char *mName;    // The name of the var.
  108.  
  109.     // sEmptyString is a special *writable* memory area for empty variables (those with zero capacity).
  110.     // Although making it writable does make buffer overflows difficult to detect and analyze (since they
  111.     // tend to corrupt the program's static memory pool), the advantages in maintainability and robustness
  112.     // see to far outweigh that.  For example, it avoids having to constantly think about whether
  113.     // *Contents()='\0' is safe. The sheer number of places that's avoided is a great relief, and it also
  114.     // cuts down on code size due to not having to always check Capacity() and/or create more functions to
  115.     // protect from writing to read-only strings, which would hurt performance.
  116.     // The biggest offender of buffer overflow in sEmptyString is DllCall, which happens most frequently
  117.     // when a script forgets to call VarSetCapacity before psssing a buffer to some function that writes a
  118.     // string to it.  That drawback has been addressed by passing the read-only empty string in place of
  119.     // sEmptyString in DllCall(), which forces an exception to occur immediately, which is caught by the
  120.     // exception handler there.
  121.     static char sEmptyString[1]; // See above.
  122.  
  123.     ResultType AssignHWND(HWND aWnd);
  124.     ResultType Assign(DWORD aValueToAssign);
  125.     ResultType Assign(int aValueToAssign);
  126.     ResultType Assign(__int64 aValueToAssign);
  127.     //ResultType Assign(unsigned __int64 aValueToAssign);
  128.     ResultType Assign(double aValueToAssign);
  129.     ResultType Assign(ExprTokenType &aToken);
  130.     ResultType AssignClipboardAll();
  131.     ResultType AssignBinaryClip(Var &aSourceVar);
  132.     ResultType Assign(char *aBuf = NULL, VarSizeType aLength = VARSIZE_MAX, bool aExactSize = false, bool aObeyMaxMem = true);
  133.     VarSizeType Get(char *aBuf = NULL);
  134.  
  135.     // Not an enum so that it can be global more easily:
  136.     #define VAR_ALWAYS_FREE                    0 // This item and the next must be first and numerically adjacent to
  137.     #define VAR_ALWAYS_FREE_BUT_EXCLUDE_STATIC 1 // each other so that VAR_ALWAYS_FREE_LAST covers only them.
  138.     #define VAR_ALWAYS_FREE_LAST               2 // Never actually passed as a parameter, just a placeholder (see above comment).
  139.     #define VAR_NEVER_FREE                     3
  140.     #define VAR_FREE_IF_LARGE                  4
  141.     void Free(int aWhenToFree = VAR_ALWAYS_FREE, bool aExcludeAliases = false);
  142.     ResultType AppendIfRoom(char *aStr, VarSizeType aLength);
  143.     void AcceptNewMem(char *aNewMem, VarSizeType aLength);
  144.     void SetLengthFromContents();
  145.  
  146.     static ResultType BackupFunctionVars(Func &aFunc, VarBkp *&aVarBackup, int &aVarBackupCount);
  147.     void Backup(VarBkp &aVarBkp);
  148.     static void FreeAndRestoreFunctionVars(Func &aFunc, VarBkp *&aVarBackup, int &aVarBackupCount);
  149.  
  150.     #define DISPLAY_NO_ERROR   0  // Must be zero.
  151.     #define DISPLAY_VAR_ERROR  1
  152.     #define DISPLAY_FUNC_ERROR 2
  153.     static ResultType ValidateName(char *aName, bool aIsRuntime = false, int aDisplayError = DISPLAY_VAR_ERROR);
  154.  
  155.     char *ToText(char *aBuf, int aBufSize, bool aAppendNewline)
  156.     // aBufSize is an int so that any negative values passed in from caller are not lost.
  157.     // Caller has ensured that aBuf isn't NULL.
  158.     // Translates this var into its text equivalent, putting the result into aBuf andp
  159.     // returning the position in aBuf of its new string terminator.
  160.     {
  161.         // Relies on the fact that aliases can't point to other aliases (enforced by UpdateAlias()).
  162.         Var &var = *(mType == VAR_ALIAS ? mAliasFor : this);
  163.         // v1.0.44.14: Changed it so that ByRef/Aliases report their own name rather than the target's/caller's
  164.         // (it seems more useful and intuitive).
  165.         char *aBuf_orig = aBuf;
  166.         aBuf += snprintf(aBuf, BUF_SPACE_REMAINING, "%s[%u of %u]: %-1.60s%s", mName // mName not var.mName (see comment above).
  167.             , var.mLength, var.mCapacity ? (var.mCapacity - 1) : 0  // Use -1 since it makes more sense to exclude the terminator.
  168.             , var.mContents, var.mLength > 60 ? "..." : "");
  169.         if (aAppendNewline && BUF_SPACE_REMAINING >= 2)
  170.         {
  171.             *aBuf++ = '\r';
  172.             *aBuf++ = '\n';
  173.             *aBuf = '\0';
  174.         }
  175.         return aBuf;
  176.     }
  177.  
  178.     __forceinline VarTypeType Type()
  179.     {
  180.         // Relies on the fact that aliases can't point to other aliases (enforced by UpdateAlias()).
  181.         return (mType == VAR_ALIAS) ? mAliasFor->mType : mType;
  182.     }
  183.  
  184.     __forceinline bool IsLocal()
  185.     {
  186.         // Since callers want to know whether this variable is local, even if it's a local alias for a
  187.         // global, don't use the method below:
  188.         //    return (mType == VAR_ALIAS) ? mAliasFor->mIsLocal : mIsLocal;
  189.         return mIsLocal;
  190.     }
  191.  
  192.     __forceinline bool IsNonStaticLocal()
  193.     {
  194.         // Since callers want to know whether this variable is local, even if it's a local alias for a
  195.         // global, don't use resolve VAR_ALIAS.
  196.         // Even a ByRef local is considered local here because callers are interested in whether this
  197.         // variable can vary from call to call to the same function (and a ByRef can vary in what it
  198.         // points to).  Variables that vary can thus be altered by the backup/restore process.
  199.         return mIsLocal && !(mAttrib & VAR_ATTRIB_STATIC);
  200.     }
  201.  
  202.     __forceinline bool IsBinaryClip()
  203.     {
  204.         // Relies on the fact that aliases can't point to other aliases (enforced by UpdateAlias()).
  205.         return (mType == VAR_ALIAS ? mAliasFor->mAttrib : mAttrib) & VAR_ATTRIB_BINARY_CLIP;
  206.     }
  207.  
  208.     void OverwriteAttrib(VarAttribType aAttrib)
  209.     {
  210.         // Relies on the fact that aliases can't point to other aliases (enforced by UpdateAlias()).
  211.         if (mType == VAR_ALIAS)
  212.             mAliasFor->mAttrib = aAttrib;
  213.         else
  214.             mAttrib = aAttrib;
  215.     }
  216.  
  217.     VarSizeType Capacity() // __forceinline() on Capacity, Length, and/or Contents bloats the code and reduces performance.
  218.     // Capacity includes the zero terminator (though if capacity is zero, there will also be a zero terminator in mContents due to it being "").
  219.     {
  220.         // Relies on the fact that aliases can't point to other aliases (enforced by UpdateAlias()).
  221.         Var &var = *(mType == VAR_ALIAS ? mAliasFor : this);
  222.         // Fix for v1.0.37: Callers want the clipboard's capacity returned, if it has a capacity.  This is
  223.         // because Capacity() is defined as being the size available in Contents(), which for the clipboard
  224.         // would be a pointer to the clipboard-buffer-to-be-written (or zero if none).
  225.         return var.mType == VAR_CLIPBOARD ? g_clip.mCapacity : var.mCapacity;
  226.     }
  227.  
  228.     VarSizeType &Length() // __forceinline() on Capacity, Length, and/or Contents bloats the code and reduces performance.
  229.     // This should not be called to discover a non-NORMAL var's length (nor that of an environment variable)
  230.     // because their lengths aren't knowable without calling Get().
  231.     // Returns a reference so that caller can use this function as an lvalue.
  232.     {
  233.         // Relies on the fact that aliases can't point to other aliases (enforced by UpdateAlias()).
  234.         Var &var = *(mType == VAR_ALIAS ? mAliasFor : this);
  235.         if (var.mType == VAR_NORMAL)
  236.             return var.mLength;
  237.         // Since the length of the clipboard isn't normally tracked, we just return a
  238.         // temporary storage area for the caller to use.  Note: This approach is probably
  239.         // not thread-safe, but currently there's only one thread so it's not an issue.
  240.         // For reserved vars do the same thing as above, but this function should never
  241.         // be called for them:
  242.         static VarSizeType length; // Must be static so that caller can use its contents. See above.
  243.         return length;
  244.     }
  245.  
  246.     VarSizeType LengthIgnoreBinaryClip()
  247.     // Returns 0 for types other than VAR_NORMAL and VAR_CLIPBOARD.
  248.     // IMPORTANT: Environment variables aren't supported here, so caller must either want such
  249.     // variables treated as blank, or have already checked that they're not environment variables.
  250.     {
  251.         // Relies on the fact that aliases can't point to other aliases (enforced by UpdateAlias()).
  252.         Var &var = *(mType == VAR_ALIAS ? mAliasFor : this);
  253.         // Return the apparent length of the string (i.e. the position of its first binary zero).
  254.         return (var.mType == VAR_NORMAL && !(var.mAttrib & VAR_ATTRIB_BINARY_CLIP))
  255.             ? var.mLength : strlen(var.Contents()); // Use Contents() vs. mContents to support VAR_CLIPBOARD.
  256.     }
  257.  
  258.     char *Contents() // __forceinline() on Capacity, Length, and/or Contents bloats the code and reduces performance.
  259.     {
  260.         // Relies on the fact that aliases can't point to other aliases (enforced by UpdateAlias()).
  261.         Var &var = *(mType == VAR_ALIAS ? mAliasFor : this);
  262.         if (var.mType == VAR_NORMAL)
  263.             return var.mContents;
  264.         if (var.mType == VAR_CLIPBOARD)
  265.             // The returned value will be a writable mem area if clipboard is open for write.
  266.             // Otherwise, the clipboard will be opened physically, if it isn't already, and
  267.             // a pointer to its contents returned to the caller:
  268.             return g_clip.Contents();
  269.         return sEmptyString; // For reserved vars (but this method should probably never be called for them).
  270.     }
  271.  
  272.     __forceinline Var *ResolveAlias()
  273.     {
  274.         // Relies on the fact that aliases can't point to other aliases (enforced by UpdateAlias()).
  275.         return (mType == VAR_ALIAS) ? mAliasFor : this; // Return target if it's an alias, or itself if not.
  276.     }
  277.  
  278.     __forceinline void ConvertToNonAliasIfNecessary() // __forceinline because it's currently only called from one place.
  279.     // When this function actually converts an alias into a normal variable, the variable's old
  280.     // attributes (especially mContents and mCapacity) become dominant again.  This prevents a memory
  281.     // leak in a case where a UDF is defined to provide a default value for a ByRef parameter, and is
  282.     // called both with and without that parameter.
  283.     {
  284.         mAliasFor = NULL; // This also sets its counterpart in the union (mLength) to zero, which is appropriate because mContents should have been set to blank by a previous call to Free().
  285.         mType = VAR_NORMAL; // It might already be this type, so this is just in case it's VAR_ALIAS.
  286.     }
  287.  
  288.     __forceinline void UpdateAlias(Var *aTargetVar) // __forceinline because it's currently only called from one place.
  289.     // Caller must ensure that aTargetVar isn't NULL.
  290.     // When this function actually converts a normal variable into an alias , the variable's old
  291.     // attributes (especially mContents and mCapacity) are hidden/suppressed by virtue of all Var:: methods
  292.     // obeying VAR_ALIAS and resolving it to be the target variable.  This prevents a memory
  293.     // leak in a case where a UDF is defined to provide a default value for a ByRef parameter, and is
  294.     // called both with and without that parameter.
  295.     {
  296.         // BELOW IS THE MEANS BY WHICH ALIASES AREN'T ALLOWED TO POINT TO OTHER ALIASES, ONLY DIRECTLY TO
  297.         // THE TARGET VAR.
  298.         // Resolve aliases-to-aliases for performance and to increase the expectation of
  299.         // reliability since a chain of aliases-to-aliases might break if an alias in
  300.         // the middle is ever allowed to revert to a non-alias (or gets deleted).
  301.         // A caller may ask to create an alias to an alias when a function calls another
  302.         // function and passes to it one of its own byref-params.
  303.         while (aTargetVar->mType == VAR_ALIAS)
  304.             aTargetVar = aTargetVar->mAliasFor;
  305.  
  306.         // The following is done only after the above in case there's ever a way for the above
  307.         // to circle back to become this variable.
  308.         // Prevent potential infinite loops in other methods by refusing to change an alias
  309.         // to point to itself.
  310.         if (aTargetVar == this)
  311.             return;
  312.  
  313.         mAliasFor = aTargetVar; // Should always be non-NULL due to various checks elsewhere.
  314.         mType = VAR_ALIAS; // It might already be this type, so this is just in case it's VAR_NORMAL.
  315.     }
  316.  
  317.     ResultType Close(bool aIsBinaryClip = false)
  318.     {
  319.         // Relies on the fact that aliases can't point to other aliases (enforced by UpdateAlias()).
  320.         Var &var = *(mType == VAR_ALIAS ? mAliasFor : this);
  321.         if (var.mType == VAR_CLIPBOARD && g_clip.IsReadyForWrite())
  322.             return g_clip.Commit(); // Writes the new clipboard contents to the clipboard and closes it.
  323.         // The binary-clip attribute is also reset here for cases where a caller uses a variable without
  324.         // having called Assign() to resize it first, which can happen if the variable's capacity is already
  325.         // sufficient to hold the desired contents.
  326.         if (aIsBinaryClip)
  327.             var.mAttrib |= VAR_ATTRIB_BINARY_CLIP;
  328.         else
  329.             var.mAttrib &= ~VAR_ATTRIB_BINARY_CLIP;
  330.         return OK; // In all other cases.
  331.     }
  332.  
  333.     // Constructor:
  334.     Var(char *aVarName, void *aType, bool aIsLocal)
  335.         // The caller must ensure that aVarName is non-null.
  336.         : mContents(sEmptyString) // Invariant: Anyone setting mCapacity to 0 must also set mContents to the empty string.
  337.         , mLength(0) // This also initializes mAliasFor within the same union.
  338.         , mHowAllocated(ALLOC_NONE)
  339.         , mAttrib(0), mIsLocal(aIsLocal)
  340.         , mName(aVarName) // Caller gave us a pointer to dynamic memory for this (or static in the case of ResolveVarOfArg()).
  341.     {
  342.         if (aType > (void *)VAR_LAST_TYPE) // Relies on the fact that numbers less than VAR_LAST_TYPE can never realistically match the address of any function.
  343.         {
  344.             mType = VAR_BUILTIN;
  345.             mBIV = (BuiltInVarType)aType; // This also initializes mCapacity within the same union.
  346.         }
  347.         else
  348.         {
  349.             mType = (VarTypeType)aType;
  350.             mCapacity = 0; // This also initializes mBIV within the same union.
  351.         }
  352.     }
  353.     void *operator new(size_t aBytes) {return SimpleHeap::Malloc(aBytes);}
  354.     void *operator new[](size_t aBytes) {return SimpleHeap::Malloc(aBytes);}
  355.     void operator delete(void *aPtr) {}
  356.     void operator delete[](void *aPtr) {}
  357. };
  358.  
  359. #endif
  360.